package edu.uts.reekie.designer.execution.actions;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.draw2d.RotatableDecoration;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.IWorkbenchPart;

import edu.uts.reekie.designer.Messages;
import edu.uts.reekie.designer.ReekieDesignerPlugin;
import edu.uts.reekie.designer.execution.edit.ConnectorEditPart;
import edu.uts.reekie.designer.execution.edit.ViewComponentEditPart;
import edu.uts.reekie.designer.execution.model.Connector;
import edu.uts.reekie.designer.execution.model.ViewComponent;
import edu.uts.reekie.designer.execution.model.ViewComponentStereotype;
import edu.uts.reekie.designer.execution.model.Connector.Decoration;
import edu.uts.reekie.designer.execution.model.commands.SetConnectorDecorationCommand;

public class SetConnectorDecorationAction 
	extends org.eclipse.gef.ui.actions.SelectionAction
	{
	
	public enum End {
		Source,Target;
	}
	
	public interface Factory {
		SetConnectorDecorationCommand createCommand();
		SetConnectorDecorationAction createAction(IWorkbenchPart part);
	}

	private static Map<String, Factory> all;
	static {
		all = new HashMap<String,Factory>();
		all.put(getId(End.Source,Decoration.Async), new Factory(){

			@Override
			public SetConnectorDecorationCommand createCommand() {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationCommand(End.Source,Decoration.Async);
			}
			@Override
			public SetConnectorDecorationAction createAction(IWorkbenchPart part) {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationAction(part, End.Source,Decoration.Async);
			}
		
		});
		all.put(getId(End.Source,Decoration.Sync), new Factory(){

			@Override
			public SetConnectorDecorationCommand createCommand() {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationCommand(End.Source,Decoration.Sync);
			}
			@Override
			public SetConnectorDecorationAction createAction(IWorkbenchPart part) {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationAction(part, End.Source,Decoration.Sync);
			}
		
		});
		all.put(getId(End.Source,Decoration.Callback), new Factory(){

			@Override
			public SetConnectorDecorationCommand createCommand() {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationCommand(End.Source,Decoration.Callback);
			}
			
			@Override
			public SetConnectorDecorationAction createAction(IWorkbenchPart part) {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationAction(part, End.Source,Decoration.Callback);
			}
		});
		all.put(getId(End.Target,Decoration.Async), new Factory(){

			@Override
			public SetConnectorDecorationCommand createCommand() {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationCommand(End.Target,Decoration.Async);
			}
			
			@Override
			public SetConnectorDecorationAction createAction(IWorkbenchPart part) {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationAction(part, End.Target,Decoration.Async);
			}
		
		});
		all.put(getId(End.Target,Decoration.Sync), new Factory(){

			@Override
			public SetConnectorDecorationCommand createCommand() {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationCommand(End.Target,Decoration.Sync);
			}
			@Override
			public SetConnectorDecorationAction createAction(IWorkbenchPart part) {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationAction(part, End.Target,Decoration.Sync);
			}
		
		});
		all.put(getId(End.Target,Decoration.Callback), new Factory(){

			@Override
			public SetConnectorDecorationCommand createCommand() {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationCommand(End.Target,Decoration.Callback);
			}
			
			@Override
			public SetConnectorDecorationAction createAction(IWorkbenchPart part) {
				// TODO Auto-generated method stub
				return new SetConnectorDecorationAction(part, End.Target,Decoration.Callback);
			}
		});
		
			
		
	}
	
	public static Map<String,Factory> all() {
		return all;
	}
	public static String[] getAllIds() {
		String[] a = new String[all.keySet().size()];
		all.keySet().toArray(a);
		return a;
	}
	
	public static String getId(End connectorEnd, Decoration decoration){
		String suffix = " to ";
		String dec = "";
		switch (decoration)
		{
		case Async:
			
			dec = "async";
			break;
		case Sync:
			dec = "sync";
			break;
		case Callback:
			dec = "callback";
		}
		
		String prefix = "Change ";
		switch (connectorEnd){
		case Source:
						prefix += "source";
						break;
		case Target:
			prefix += "target";
			break;
		}
		
		return prefix + suffix + dec;
		
	}


	Request request;
	private End end;
	private Decoration decoration;
	private static int count = 0;
	private int c;

	public SetConnectorDecorationAction(IWorkbenchPart part, End connectorEnd, Decoration decoration) {
		super(part);
		
		this.end = connectorEnd;
		this.decoration = decoration;
		this.c = count++;
		String id = getId(connectorEnd,decoration);
		
		request = new Request(id);
		setText(id);
		setToolTipText(id);
		setId(id);
		// TODO: change to real icon
		setImageDescriptor(
				ImageDescriptor.createFromFile(ReekieDesignerPlugin.class,"icons/plus.gif")); //$NON-NLS-1$
			
		
		setHoverImageDescriptor(getImageDescriptor());
	}

	protected boolean calculateEnabled() {
		return canPerformAction();
	}

	private boolean canPerformAction() {
		
		if (getSelectedObjects().isEmpty())
			return false;
		
		
		List<?> parts = getSelectedObjects();
		for (int i=0; i<parts.size(); i++){
			Object o = parts.get(i);
			if (!(o instanceof ConnectorEditPart))
				return false;
			
			ConnectorEditPart part = (ConnectorEditPart)o;
			if (!(part.getModel() instanceof Connector))
				return false;
			
			Connector model = (Connector)part.getModel();
			switch (end){
			case Target:
				if (model.getTargetDecoration()==decoration)
					return false;
				break;
			case Source:
				if (model.getSourceDecoration()==decoration || model.getDirection()==Connector.UNIDIRECTIONAL_CONNECTION)
					return false;
				break;
			}
						
		}
		return true;
	}

	private Command getCommand() {
		
		List editparts = getSelectedObjects();
		CompoundCommand cc = new CompoundCommand();
		cc.setDebugLabel(getId());//$NON-NLS-1$
		for (int i=0; i < editparts.size(); i++) {
			EditPart part = (EditPart)editparts.get(i);
			cc.add(part.getCommand(request));
		}
		return cc;
	}

	public void run() {
		execute(getCommand());
	}
}
